"use strict";

var gHrTimeBase = process.hrtime();  // 返回的是当前的高分辨率时间，格式为[秒, 纳秒]。它是相对于在过去的任意时间，该值与日期无关。
var gMSBase = Date.now();
var gLastHr = null;
function logTSBegin(info) {
    gHrTimeBase = process.hrtime();
    gMSBase = Date.now();
    gLastHr = null;
    console.log("\n0ms, " + info);
}

// scale: sec 时间戳精确到秒，ms 时间戳精确到毫秒，us 时间戳精确到微秒，ns时间戳精确到纳秒
function logTS(info, scale) {
    const hrDiff = process.hrtime(gHrTimeBase);
    const nowMS = Date.now();

    scale = scale || 'ms';
    let tsStr = '';
    switch (scale) {
        case 'ms':
            tsStr = (nowMS - gMSBase) + 'ms';// 计算距时间戳base, 消耗的时间，单位ms
            if (gLastHr) {
                // 计算距离上一次 logTS 调用消耗的时间，单位ms
                let deltaFromLast = (hrDiff[0] - gLastHr[0]) * 1000 + parseInt((hrDiff[1] - gLastHr[1]) / 1e6);
                tsStr = '+' + deltaFromLast + '->' + tsStr
            }
            break;
        case 'sec':
            tsStr = parseInt((nowMS - gMSBase) / 1000) + 'sec';// 计算距时间戳base, 消耗的时间，单位sec
            if (gLastHr) {
                // 计算距离上一次 logTS 调用消耗的时间，单位sec
                tsStr = '+' + (hrDiff[0] - gLastHr[0]) + '->' + tsStr
            }
            break;
        case 'us':
            let diffInUs = parseInt(hrDiff[0] * 1e6 + hrDiff[1] / 1000);// 计算距时间戳base, 消耗的时间，单位us
            tsStr = diffInUs + 'us'
            if (gLastHr) {
                // 计算距离上一次 logTS 调用消耗的时间，单位us
                let deltaFromLast = (hrDiff[0] - gLastHr[0]) * 1e6 + parseInt((hrDiff[1] - gLastHr[1]) / 1000);
                tsStr = '+' + deltaFromLast + '->' + tsStr
            }
            break;
        case 'ns':
            const diffInNS = hrDiff[0] * 1e9 + hrDiff[1];// 计算距时间戳base, 消耗的时间，单位ns
            tsStr = diffInNS + 'ns'
            if (gLastHr) {
                // 计算距离上一次 logTS 调用消耗的时间，单位ns
                let deltaFromLast = (hrDiff[0] - gLastHr[0]) * 1e9 + (hrDiff[1] - gLastHr[1]);
                tsStr = '+' + deltaFromLast + '->' + tsStr
            }
            break;
        default:
    }
    gLastHr = hrDiff;
    console.log("\n" + tsStr + ", " + info);
}

function timeStamp() {
    const hrBase = process.hrtime();  // 返回的是当前的高分辨率时间，格式为[秒, 纳秒]。它是相对于在过去的任意时间，该值与日期无关。
    let dateNow = new Date();

    // 日期对象 --> 时间戳
    // https://blog.csdn.net/qq_44741441/article/details/122990466

    //   秒时间戳
    console.log("秒时间戳 form Date.now = " + parseInt(Date.now() / 1000));

    //   毫秒时间戳 1e-3
    let tsMS = dateNow.getTime(); // 当前日期时间 的 毫秒时间戳
    console.log("毫秒时间戳 form getTime = " + tsMS);
    console.log("毫秒时间戳 form Date.now = " + Date.now());

    //   微秒时间戳 1e-6
    const hrDiff = process.hrtime(hrBase);  // 计算 从hrBase 到当前的 精确时间消耗，返回一个包含两个元素的数组
    const diffFromBaseInUs = parseInt(hrDiff[0] * 1e6 + hrDiff[1] / 1000);  // hrDiff[0] 单位秒 hrDiff[1] 单位 纳秒
    let tsUS = tsMS * 1000 + diffFromBaseInUs;
    console.log("微秒时间戳 form process.hrtime = " + tsUS + ', diffFrom base in ns=' + hrDiff[1]);


    //   纳秒时间戳 1e-9
    const hrDiffNS = process.hrtime(hrBase);
    const diffFromBaseInNS = hrDiffNS[0] * 1e9 + hrDiffNS[1];  // hrDiff[0] 单位秒 hrDiff[1] 单位 纳秒
    let tsNS = tsMS * 1e6 + diffFromBaseInNS;
    console.log("纳秒时间戳 form process.hrtime = " + tsNS + ', diffFrom base in ns=' + hrDiffNS[1]);

    // 时间戳 --> 日期对象
    const yestodayMS = tsMS - 86400 * 1000;
    let yestodayDate = new Date(yestodayMS);
    console.log("此时此刻 " + dateNow);
    console.log("昨天此时 " + yestodayDate);
}

// 仿造 java SimpleDateFormat 字符串格式化，做js的 Date 对象的 字符串格式化
function simpleDateFormat(dateObj, fmt) {

    /*
    https://blog.csdn.net/qq_36761831/article/details/79691119
    java SimpleDateFormat 函数语法：
    
     G 年代标志符
     y 年
     M 月
     d 日
     h 时 在上午或下午 (1~12)
     H 时 在一天中 (0~23)
     m 分
     s 秒
     S 毫秒
     E 星期
     D 一年中的第几天
     F 一月中第几个星期几
     w 一年中第几个星期
     W 一月中第几个星期
     a 上午 / 下午 标记符
     k 时 在一天中 (1~24)
     K 时 在上午或下午 (0~11)
     z 时区
     */

    // https://blog.csdn.net/lzg1169350237/article/details/71237445
    if (!(dateObj instanceof Date)) {
        return ''
    }

    /**     
     * 对Date的扩展，将 Date 转化为指定格式的String     
     * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q) 可以用 1-2 个占位符     
     * 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)     
     * eg:     
     * (new Date()).pattern("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423     
     * (new Date()).pattern("yyyy-MM-dd E HH:mm:ss") ==> 2009-03-10 二 20:09:04     
     * (new Date()).pattern("yyyy-MM-dd EE hh:mm:ss") ==> 2009-03-10 周二 08:09:04     
     * (new Date()).pattern("yyyy-MM-dd EEE hh:mm:ss") ==> 2009-03-10 星期二 08:09:04     
     * (new Date()).pattern("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18     
     *
     * 使用：(eval(value.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"))).pattern("yyyy-M-d h:m:s.S");
     *
     */

    let patternDic = {
        "M+": dateObj.getMonth() + 1, //月份        
        "d+": dateObj.getDate(), //日        
        "h+": dateObj.getHours() % 12 == 0 ? 12 : dateObj.getHours() % 12, //小时        
        "H+": dateObj.getHours(), //小时        
        "m+": dateObj.getMinutes(), //分        
        "s+": dateObj.getSeconds(), //秒        
        "q+": Math.floor((dateObj.getMonth() + 3) / 3), //季度        
        "S": dateObj.getMilliseconds() //毫秒        
    };
    let weekDic = {
        "0": "/u65e5",
        "1": "/u4e00",
        "2": "/u4e8c",
        "3": "/u4e09",
        "4": "/u56db",
        "5": "/u4e94",
        "6": "/u516d"
    };

    if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(RegExp.$1, (dateObj.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
    if (/(E+)/.test(fmt)) {
        fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + weekDic[dateObj.getDay() + ""]);
    }
    for (var k in patternDic) {
        if (new RegExp("(" + k + ")").test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (patternDic[k]) : (("00" + patternDic[k]).substr(("" + patternDic[k]).length)));
        }
    }
    return fmt;

}

function datetime2String() {
    console.log("\ndatetime2String");

    let dateNow = new Date();

    console.log('string + date obj  -> ' + dateNow);                        // 字符串连接 ：                Wed Nov 02 2022 11:17:25 GMT+0800 (中国标准时间)
    console.log('toString           -> ' + dateNow.toString());             // 转换为字符串 ：              Wed Nov 02 2022 11:17:25 GMT+0800 (中国标准时间)
    console.log('toDateString       -> ' + dateNow.toDateString());         // 日期字符串 ：                Wed Nov 02 2022
    console.log('toTimeString       -> ' + dateNow.toTimeString());         // 时间字符串 ：                11:17:25 GMT+0800 (中国标准时间)
    console.log('toGMTString        -> ' + dateNow.toGMTString());          // 格林威治时间 ：              Wed, 02 Nov 2022 03:17:25 GMT
    console.log('toUTCString        -> ' + dateNow.toUTCString());          // 转换为世界时间 ：             Wed, 02 Nov 2022 03:17:25 GMT
    console.log('toISOString        -> ' + dateNow.toISOString());          // 国际标准组织（ISO）格式 ：     2022-11-02T03:17:25.228Z
    console.log('toJSON             -> ' + dateNow.toJSON());               // json输出：                  2022-11-02T03:17:25.228Z
    console.log('toLocaleDateString -> ' + dateNow.toLocaleDateString());   // 本地日期格式，视环境而定 ：     2022/11/2
    console.log('toLocaleString     -> ' + dateNow.toLocaleString());       // 本地日期和时间格式，视环境而定 ：2022/11/2 11:17:25
    console.log('toLocaleTimeString -> ' + dateNow.toLocaleTimeString());   // 本地时间格式，视环境而定 ：     11:17:25

    console.log('yyyy-MM-dd HH:mm:ss S -> ' + simpleDateFormat(dateNow, 'yyyy-MM-dd HH:mm:ss S'));
    console.log('yy年MM月dd日 HH时mm分ss秒 S毫秒 -> ' + simpleDateFormat(dateNow, 'yy年MM月dd日 HH时mm分ss秒 S毫秒'));
    console.log('yy年M月d日 H时m分s秒 S毫秒 -> ' + simpleDateFormat(dateNow, 'yy年M月d日 H时m分s秒 S毫秒'));
}

function string2Datetime() {

    console.log("\nstring2Datetime");

    // 试验 如下几种日期格式字符串，Date 可以成功构建
    let dtStr = '2022-9-2 14:8:3';
    let dateFromStr = new Date(dtStr);
    console.log(dtStr + ' -> ' + dateFromStr.toLocaleString());

    dtStr = '2022-09-02 14:08:03';
    dateFromStr = new Date(dtStr);
    console.log(dtStr + ' -> ' + dateFromStr.toLocaleString());

    dtStr = '2022/09/02 14:08:03';
    dateFromStr = new Date(dtStr);
    console.log(dtStr + ' -> ' + dateFromStr.toLocaleString());

    dtStr = '2022/09/02';
    dateFromStr = new Date(dtStr);
    console.log(dtStr + ' -> ' + dateFromStr.toLocaleString());

    dtStr = '2022-9-2';
    dateFromStr = new Date(dtStr);
    console.log(dtStr + ' -> ' + dateFromStr.toLocaleString());
}

function demoLogic() {
    //console.log("\ndateDemoLogic");
    timeStamp();
    datetime2String();
    string2Datetime();
}

export { demoLogic, logTSBegin, logTS, simpleDateFormat };